package org.vectrics.common.db;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;
import org.apache.log4j.Logger;
import org.vectrics.SystemException;

public class ExpirableUtils {
	private static final Logger log = Logger.getLogger(ExpirableUtils.class);

	public static Expirable getCurrent(Collection expirables) {
		log.debug("getCurrent(expirables) called");
		Expirable currentExp = null;
    	Iterator iter = expirables.iterator();
    	while (iter.hasNext()) {
    		Expirable exp = (Expirable)iter.next();
    		boolean voided = false;
    		if (exp instanceof Voidable) {
    			Voidable voidable = (Voidable)exp;
    			if (voidable.getVoided()) {
    				voided = true;
    			}
    		}
    		
    		if (voided == false) {
    			if (exp.getDateEnd() == null) {
    				if (currentExp == null)
    					currentExp = exp;
    				else
    					throw new SystemException("At least two expirables are current - have null end dates, illegal state");
    			}
    		}
    	}
    	return(currentExp);
    }
    
    
    public static List sortExpirablesByStartDate(Collection expirables) {
    	List list = new ArrayList();
    	TreeSet sorted = new TreeSet(new ExpirableStartDateComparator());
    	sorted.addAll(expirables);
    	list.addAll(sorted);
    	return(list);
    }
    
    public static ValidationProblemList validateNoOverlap(Collection expirables) {
    	ValidationProblemList problems = new ValidationProblemList();
    	Expirable previous = null;
    	List sortedList = sortExpirablesByStartDate(expirables);
    	Iterator iter = sortedList.iterator();
    	while (iter.hasNext()) {
    		boolean voided = false;
    		Expirable exp = (Expirable)iter.next();
			if (exp instanceof Voidable) {
				Voidable voidable = (Voidable)exp;
				if (voidable.getVoided())
					voided = true;
			}
			if (voided == false) {
				if (previous != null) {
					if (previous.getDateEnd().after(exp.getDateStart())) {
						OverlapValidationProblem problem = new OverlapValidationProblem();
						problem.addExpirable(previous);
						problem.addExpirable(exp);
						problems.add(problem);
					}
				}
			}
			previous = exp;
    	}
    	return(problems);
    }

    public static ValidationProblemList validateNoGapsNoEnd(Collection expirables) {
    	return(validateNoGaps(expirables, true));
    }

    public static ValidationProblemList validateNoGaps(Collection expirables) {
    	return(validateNoGaps(expirables, false));
    }
    
    public static ValidationProblemList validateNoGaps(Collection expirables, boolean noEnd) {
    	ValidationProblemList validationProblems = new ValidationProblemList();
    	
    	Expirable previous = null;
    	List sortedList = sortExpirablesByStartDate(expirables);
    	Iterator iter = sortedList.iterator();
    	while (iter.hasNext()) {
    		boolean voided = false;
    		Expirable exp = (Expirable)iter.next();
			if (exp instanceof Voidable) {
				Voidable voidable = (Voidable)exp;
				if (voidable.getVoided())
					voided = true;
			}
			if (voided == false) {
				if (previous != null) {
					if (previous.getDateEnd() == null)
						throw new SystemException("Expirable element not at end of list has null end date. " +
								"\r\n - Object = " + previous
								+ "\r\n - All elements: " + ExpirableUtils.getDebugString(expirables));
					if (previous.getDateEnd().before(exp.getDateStart())) {
						GapValidationProblem problem = new GapValidationProblem();
						problem.setExpirable1(previous);
						problem.setExpirable2(exp);
						validationProblems.add(problem);
					}
				}
			}
			previous = exp;
    	}
    	if (previous != null) {
    		if (previous.getDateEnd() != null) {
    			NoCoverageValidationProblem problem = new NoCoverageValidationProblem();
    			problem.setStartDate(previous.getDateEnd());
    			problem.setEndDate(null);
    			validationProblems.add(problem);
    		}
    	} else {
			NoCoverageValidationProblem problem = new NoCoverageValidationProblem();
			problem.setStartDate(null);
			problem.setEndDate(null);
			validationProblems.add(problem);
    	}
    	return(validationProblems);
    }
    
    
    public static String getDebugString(Collection expirables) {
    	SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:s.S");
    	List list = sortExpirablesByStartDate(expirables); 
    	
    	StringBuffer str = new StringBuffer();
    	str.append("\r\n " + list.size() + " Elements");
    	Iterator iter = list.iterator();
    	while (iter.hasNext()) {
    		Expirable exp = (Expirable)iter.next();
    		str.append("\r\n       - ");
    		if (exp.getDateStart() != null)
    			str.append(format.format(exp.getDateStart()));
    		else
    			str.append("NULL");
    			
    		str.append("   to   ");
    		if (exp.getDateEnd() != null)
    			str.append(format.format(exp.getDateEnd()));
    		else
    			str.append("NULL");
    		
    		String objToString = exp.toString();
    		if (objToString.length() > 90)
    			objToString = objToString.substring(0, 90);
    		str.append(" -->\r\n        " + objToString);
    	}
    	return(str.toString());
    }


    
}
